package lxs.swift.instance;


import lxs.swift.tool.Dater;
import lxs.swift.verify.Verifies;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Stream;

public class Instances {
    public static <T> T forceCast(Object value) {
        return ((T) value);
    }

    /**
     * 映射器
     */
    public interface Mapper {
        /**
         * 将多个值用符号分割映射成一个字符串
         *
         * @param delimiter 分隔符
         * @param keys      keys
         * @return Function<HashStruct, String>
         */
        static Function<HashStruct, String> joinString(String delimiter, String... keys) {
            if (Verifies.isEmpty(delimiter)) throw new RuntimeException("delimiter不能为空");
            Objects.requireNonNull(keys);
            if (keys.length == 0) throw new RuntimeException("请传入至少一个key");
            return struct -> {
                List<Object> list = struct.action().objects().values(keys);
                String[] strings = new String[list.size()];
                for (int i = 0; i < list.size(); i++) {
                    Object o = list.get(i);
                    strings[i] = String.valueOf(o);
                }
                return String.join(delimiter, strings);
            };
        }

        /**
         * 将Struct对象映射为一个String类型对象
         *
         * @param key key值
         * @return Function<HashStruct, String> toString
         */
        static Function<HashStruct, String> toString(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().strings().get(key);
        }

        /**
         * 将Struct对象映射为一个Boolean类型对象
         *
         * @param key key值
         * @return Function<HashStruct, Boolean> toBoolean
         */
        static Function<HashStruct, Boolean> toBoolean(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().bools().get(key);
        }

        /**
         * 将Struct对象映射为一个Character类型对象
         *
         * @param key key值
         * @return Function<HashStruct, Character> toChar
         */
        static Function<HashStruct, Character> toChar(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().strings().getOr(key, "").charAt(0);
        }

        /**
         * 将Struct对象映射为一个Integer类型对象
         *
         * @param key key值
         * @return Function<HashStruct, Integer> toInt
         */
        static Function<HashStruct, Integer> toInt(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().ints().get(key);
        }

        /**
         * 将Struct对象映射为一个Long类型对象
         *
         * @param key key值
         * @return Function<HashStruct, Long> toLong
         */
        static Function<HashStruct, Long> toLong(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().longs().get(key);
        }

        /**
         * 将Struct对象映射为一个Double类型对象
         *
         * @param key key值
         * @return Function<HashStruct, Double> toDouble
         */
        static Function<HashStruct, Double> toDouble(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().doubles().get(key);
        }

        /**
         * 传入一个对象返回对象本身
         *
         * @return Function<T, T> toSelf
         */
        static <T> Function<T, T> toSelf() {
            return self -> self;
        }


        /**
         * 将Struct对象映射为一个Integer类型对象,用于在Stream流中排序、统计和比较
         *
         * @param key key值
         * @return ToDoubleFunction<HashStruct> mapToInt
         */
        static ToIntFunction<HashStruct> mapToInt(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().ints().get(key);
        }

        /**
         * 将Struct对象映射为一个Long类型对象,用于在Stream流中排序、统计和比较
         *
         * @param key key值
         * @return ToDoubleFunction<HashStruct> mapToLong
         */
        static ToLongFunction<HashStruct> mapToLong(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().longs().get(key);
        }

        /**
         * 将Struct对象映射为一个Double类型对象,用于在Stream流中排序、统计和比较
         *
         * @param key key值
         * @return ToDoubleFunction<HashStruct> mapToDouble
         */
        static ToDoubleFunction<HashStruct> mapToDouble(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> struct.action().doubles().get(key);
        }

        /**
         * 将字符串形式的时间转换成毫秒值,用于在Stream流中排序、统计和比较
         *
         * @param key key值
         * @return ToLongFunction<HashStruct>mapToTimeMillis
         */
        static ToLongFunction<HashStruct> mapToTimeMillis(String key) {
            if (Verifies.isEmpty(key)) throw new RuntimeException("key不能为空");
            return struct -> {
                String string = struct.action().strings().get(key);
                Date date = Dater.parse(string).date;
                return date.getTime();
            };
        }

    }

    /**
     * 过滤器
     */
    public interface Filter {
        /**
         * Integer类型数值范围过滤器
         *
         * @param map        映射器
         * @param min        最小的值
         * @param max        最大的值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<T> intFilter
         */
        public static <T> Predicate<T> intFilter(Function<T, Integer> map, int min, int max, boolean nullIgnore) {
            Objects.requireNonNull(map);
            return item -> {
                Integer value = map.apply(item);
                if (value == null) return nullIgnore;
                return value >= min && value < max;
            };
        }

        /**
         * Long类型数值范围过滤器
         *
         * @param map        映射器
         * @param min        最小的值
         * @param max        最大的值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<T> longFilter
         */

        public static <T> Predicate<T> longFilter(Function<T, Long> map, long min, long max, boolean nullIgnore) {
            Objects.requireNonNull(map);
            return item -> {
                Long value = map.apply(item);
                if (value == null) return nullIgnore;
                return value >= min && value < max;
            };
        }


        /**
         * double类型数值范围过滤器
         *
         * @param map        映射器
         * @param min        最小的值
         * @param max        最大的值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<T> doubleFilter
         */

        public static <T> Predicate<T> doubleFilter(Function<T, Double> map, double min, double max, boolean nullIgnore) {
            Objects.requireNonNull(map);
            return item -> {
                Double value = map.apply(item);
                if (value == null) return nullIgnore;
                return value >= min && value < max;
            };
        }


        /**
         * 时间范围过滤器
         *
         * @param map        映射器
         * @param min        最小的值
         * @param max        最大的值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<T> dateFilter
         */

        public static <T> Predicate<T> dateFilter(Function<T, Date> map, Date min, Date max, boolean nullIgnore) {
            Objects.requireNonNull(map);
            long minTime = min.getTime();
            long maxTime = max.getTime();
            return longFilter(map.andThen(date -> {
                if (Verifies.isEmpty(date)) return null;
                return date.getTime();
            }), minTime, maxTime, nullIgnore);
        }

        /**
         * 时间范围过滤器
         *
         * @param map        映射器
         * @param min        最小的值
         * @param max        最大的值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<T> dateFilter
         */

        public static <T> Predicate<T> dateFilter(Function<T, String> map, String min, String max, boolean nullIgnore) {
            Objects.requireNonNull(map);
            long minTime = Dater.parse(min).date.getTime();
            long maxTime = Dater.parse(max).date.getTime();
            return longFilter(map.andThen(str -> {
                if (Verifies.isEmpty(str)) return null;
                return Dater.parse(str).date.getTime();
            }), minTime, maxTime, nullIgnore);

        }


        /**
         * null值过滤器
         *
         * @param map      映射器
         * @param nullAble false表示过滤出对应的值不为null的元素
         * @return Predicate<HashStruct> nullFilter
         */
        public static <T, R> Predicate<T> nullFilter(Function<T, R> map, boolean nullAble) {
            Objects.requireNonNull(map);
            return item -> {
                R value = map.apply(item);
                if (nullAble) return value == null;
                return value != null;
            };
        }

        /**
         * 字符串元素空串或者null值的过滤器
         *
         * @param map       映射器
         * @param emptyAble false表示过滤出key对应的值不为null且不为空串的元素
         * @return Predicate<HashStruct> nullFilter
         */
        public static <T> Predicate<T> emptyFilter(Function<T, String> map, boolean emptyAble) {
            Objects.requireNonNull(map);
            return item -> {
                String value = map.apply(item);
                if (emptyAble) return value == null || value.isEmpty();
                return value != null && !value.isEmpty();
            };
        }

        /**
         * 值过滤器,Struct对象中对应的值必须完全等于期望值
         *
         * @param map        映射器
         * @param expect     期望值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<HashStruct> unequalFilter
         */
        public static <T, R> Predicate<T> equalFilter(Function<T, R> map, R expect, boolean nullIgnore) {
            Objects.requireNonNull(map);
            return item -> {
                R value = map.apply(item);
                if (value == null) return nullIgnore;
                return value.equals(expect);
            };
        }

        /**
         * 值过滤器,Struct对象中对应的值必须不等于期望值
         *
         * @param map        将Struct映射为一个泛型对象
         * @param expect     期望值
         * @param nullIgnore 当元素为空时的返回值
         * @return Predicate<HashStruct> unequalFilter
         */
        public static <T, R> Predicate<T> unequalFilter(Function<T, R> map, R expect, boolean nullIgnore) {
            Objects.requireNonNull(map);
            return item -> {
                R value = map.apply(item);
                if (value == null) return nullIgnore;
                return !value.equals(expect);
            };
        }

        /**
         * 值过滤器,Struct对象中对应的值必须包含于目标集合
         *
         * @param mapTo      将Struct映射为一个泛型对象
         * @param collection 目标集合
         * @return Predicate<HashStruct> containsFilter
         */
        public static <T, R> Predicate<T> containsFilter(Function<T, R> mapTo, Collection<R> collection, boolean nullIgnore) {
            Objects.requireNonNull(mapTo);
            Objects.requireNonNull(collection);
            return item -> {
                R value = mapTo.apply(item);
                if (value == null) return nullIgnore;
                return collection.contains(value);
            };
        }

        /**
         * 值过滤器,Struct对象中对应的值必须不包含于目标集合
         *
         * @param mapTo      将Struct映射为一个泛型对象
         * @param collection 目标集合
         * @return Predicate<HashStruct> unContainsFilter
         */
        public static <T, R> Predicate<T> unContainsFilter(Function<T, R> mapTo, Collection<R> collection, boolean nullIgnore) {
            Objects.requireNonNull(mapTo);
            Objects.requireNonNull(collection);
            return item -> {
                R value = mapTo.apply(item);
                if (value == null) return nullIgnore;
                return !collection.contains(value);
            };
        }

        /**
         * 值过滤器,Struct对象中对应的String值必须包含于目标String
         *
         * @param mapTo  将Struct映射为一个泛型对象
         * @param string 目标String
         * @return Predicate<HashStruct> containsFilter
         */
        public static <T> Predicate<T> containsFilter(Function<T, String> mapTo, String string, boolean nullIgnore) {
            Objects.requireNonNull(mapTo);
            Objects.requireNonNull(string);
            return item -> {
                String value = mapTo.apply(item);
                if (value == null) return nullIgnore;
                return string.contains(value);
            };
        }

        /**
         * 值过滤器,Struct对象中对应的String值必须不包含于目标String
         *
         * @param mapTo  将Struct映射为一个泛型对象
         * @param string 目标String
         * @return Predicate<HashStruct> unContainsFilter
         */
        public static <T> Predicate<T> unContainsFilter(Function<T, String> mapTo, String string, boolean nullIgnore) {
            Objects.requireNonNull(mapTo);
            Objects.requireNonNull(string);
            return item -> {
                String value = mapTo.apply(item);
                if (value == null) return nullIgnore;
                return !string.contains(value);
            };
        }
    }

    /**
     * 比较器
     */
    public interface Comparer {
        /**
         * int类型的排序器
         *
         * @param map    映射器
         * @param ifNULL 当元素为null时的返回值
         * @param isDESC 是否为倒序
         * @return Comparator<HashStruct> intComparator
         */
        public static <T> Comparator<T> intComparator(Function<T, Integer> map, int ifNULL, boolean isDESC) {
            Objects.requireNonNull(map);
            Comparator<T> comparator = Comparator.comparingInt(item -> {
                Integer v = map.apply(item);
                if (v == null) return ifNULL;
                return v;
            });
            if (isDESC) return Collections.reverseOrder(comparator);
            return comparator;
        }

        /**
         * long类型的排序器
         *
         * @param map    映射器
         * @param ifNULL 当元素为null时的返回值
         * @param isDESC 是否为倒序
         * @return Comparator<HashStruct> longComparator
         */
        public static <T> Comparator<T> longComparator(Function<T, Long> map, long ifNULL, boolean isDESC) {
            Objects.requireNonNull(map);
            Comparator<T> comparator = Comparator.comparingLong(item -> {
                Long v = map.apply(item);
                if (v == null) return ifNULL;
                return v;
            });
            if (isDESC) return Collections.reverseOrder(comparator);
            return comparator;
        }

        /**
         * double类型的排序器
         *
         * @param map    映射器
         * @param ifNULL 当元素为null时的返回值
         * @param isDESC 是否为倒序
         * @return Comparator<HashStruct> doubleComparator
         */
        public static <T> Comparator<T> doubleComparator(Function<T, Double> map, double ifNULL, boolean isDESC) {
            Objects.requireNonNull(map);
            Comparator<T> comparator = Comparator.comparingDouble(item -> {
                Double v = map.apply(item);
                if (v == null) return ifNULL;
                return v;
            });
            if (isDESC) return Collections.reverseOrder(comparator);
            return comparator;
        }

        /**
         * 时间类型的排序器
         *
         * @param map    映射器
         * @param ifNULL 当元素为null时的返回值
         * @param isDESC 是否为倒序
         * @return Comparator<HashStruct> dateComparator
         */
        public static <T> Comparator<T> dateComparator(Function<T, Date> map, String ifNULL, boolean isDESC) {
            Objects.requireNonNull(map);
            long datetime = Dater.parse(ifNULL).date.getTime();
            Comparator<T> comparator = Comparator.comparingLong(item -> {
                Date v = map.apply(item);
                if (v == null) return datetime;
                return v.getTime();
            });
            if (isDESC) return Collections.reverseOrder(comparator);
            return comparator;
        }
    }

    /**
     * 扁平器
     */
    public interface Flattener {


        /**
         * 批量映射
         *
         * @param mapTo 映射函数
         * @param <R>   泛型
         * @return 一组泛型对象集合
         */
        public static <T, R> Function<Collection<T>, Stream<R>> flat(Function<T, R> mapTo) {
            Objects.requireNonNull(mapTo);
            return list -> {
                List<R> rList = new ArrayList<>();
                for (T item : list) {
                    rList.add(mapTo.apply(item));
                }
                return rList.stream();
            };
        }


    }

    /**
     * 累加器
     */
    public interface Accumulator {
        /**
         * 将keys中的所有int值按对应key累加
         *
         * @param keys keys
         * @return 多key int累加器
         */
        public static BinaryOperator<HashStruct> intAccumulator(String... keys) {
            Objects.requireNonNull(keys);
            if (keys.length == 0) throw new RuntimeException("请传入至少一个key");
            return (struct1, struct2) -> {
                HashStruct struct = new HashStruct();
                for (String key : keys) {
                    int v1 = struct1.action().ints().getOr(key, 0);
                    int v2 = struct2.action().ints().getOr(key, 0);
                    struct.put(key, v1 + v2);
                }
                return struct;
            };
        }

        /**
         * 将keys中的所有值保留到聚合结果中，如果两个对应的值不一致，则报错
         *
         * @param keys keys
         * @return 多key int累加器
         */
        public static BinaryOperator<HashStruct> saveAccumulator(String... keys) {
            Objects.requireNonNull(keys);
            if (keys.length == 0) throw new RuntimeException("请传入至少一个key");
            int[] counter = {0};
            return (struct1, struct2) -> {
                HashStruct struct = new HashStruct();
                for (String key : keys) {
                    Object v1 = struct1.get(key);
                    Object v2 = struct2.get(key);
                    if (counter[0] == 0) v1 = v2;
                    if (v1 == null && v2 == null) {
                        struct.put(key, null);
                        continue;
                    } else if (v1 != null && v1.equals(v2)) {
                        struct.put(key, v1);
                        continue;
                    }
                    throw new RuntimeException("key:" + key + "对应的结果不相同,无法在聚合中保留");

                }
                counter[0]++;
                return struct;
            };
        }

        /**
         * 将keys中的所有long值按对应key累加
         *
         * @param keys keys
         * @return 多key long累加器
         */
        public static BinaryOperator<HashStruct> longAccumulator(String... keys) {
            Objects.requireNonNull(keys);
            if (keys.length == 0) throw new RuntimeException("请传入至少一个key");
            return (struct1, struct2) -> {
                HashStruct struct = new HashStruct();
                for (String key : keys) {
                    long v1 = struct1.action().longs().getOr(key, 0L);
                    long v2 = struct2.action().longs().getOr(key, 0L);
                    struct.put(key, v1 + v2);
                }
                return struct;
            };
        }

        /**
         * 将keys中的所有double值按对应key累加
         *
         * @param keys keys
         * @return 多key double累加器
         */
        public static BinaryOperator<HashStruct> doubleAccumulator(String... keys) {
            Objects.requireNonNull(keys);
            if (keys.length == 0) throw new RuntimeException("请传入至少一个key");
            return (struct1, struct2) -> {
                HashStruct struct = new HashStruct();
                for (String key : keys) {
                    double v1 = struct1.action().doubles().getOr(key, 0.0);
                    double v2 = struct2.action().doubles().getOr(key, 0.0);
                    struct.put(key, v1 + v2);
                }
                return struct;
            };
        }

        /**
         * 将所有累加器按顺序执行,最后将结果合并
         *
         * @param accumulators 累加器数组
         * @return 多key 累加器
         */
        @SafeVarargs
        public static BinaryOperator<HashStruct> accumulator(BinaryOperator<HashStruct>... accumulators) {
            Objects.requireNonNull(accumulators);
            if (accumulators.length == 0) throw new RuntimeException("请传入至少一个累加器");
            return (struct1, struct2) -> {
                HashStruct struct = new HashStruct();
                for (BinaryOperator<HashStruct> accumulator : accumulators) {
                    HashStruct apply = accumulator.apply(struct1, struct2);
                    struct.putAll(apply);
                }
                return struct;
            };
        }
    }

    public static class Collector0 {
        /**
         * 传入一组由key和Predicate函数组成的断言对象,返回一个统计Struct集合里符合各个规则数量的Collector
         * 该Collector返回一个HashStruct,通过断言对象的key可以从中获取出每个断言的统计值
         *
         * @param predicates 断言对象数组
         * @return Collector<HashStruct, Map < Predicate < HashStruct>, Long>, Map<Predicate<HashStruct>, Long>> statistics
         */
        @SafeVarargs
        public static Collector<HashStruct, Map<Predicate<HashStruct>, Long>, Map<Predicate<HashStruct>, Long>> statistics(Predicate<HashStruct>... predicates) {
            Objects.requireNonNull(predicates);
            Supplier<Map<Predicate<HashStruct>, Long>> supplier = HashMap::new;
            BiConsumer<Map<Predicate<HashStruct>, Long>, HashStruct> accumulator = (r, t) -> {
                for (Predicate<HashStruct> predicate : predicates) {
                    if (predicate.test(t)) {
                        Long aLong = r.computeIfAbsent(predicate, k -> 0L);
                        r.put(predicate, aLong + 1);
                    }
                }
            };
            BinaryOperator<Map<Predicate<HashStruct>, Long>> combiner = (left, right) -> {
                for (Predicate<HashStruct> predicate : predicates) {
                    Long aLong = left.computeIfAbsent(predicate, k -> 0L);
                    left.put(predicate, aLong + right.computeIfAbsent(predicate, k -> 0L));
                }
                return left;
            };
            return Collector.of(supplier, accumulator, combiner);
        }


        /**
         * 当 Collectors.toMap 出现key值重复时,选择老的元素
         */
        public static <R> BinaryOperator<R> LEFT_ITEM() {
            return (v1, v2) -> v1;
        }

        /**
         * 当 Collectors.toMap 出现key值重复时,选择新的元素
         */
        public static <R> BinaryOperator<R> RIGHT_ITEM() {
            return (v1, v2) -> v2;
        }


        public static void batchCopies(List<HashStruct> list, Map<String, String> map) {
            Objects.requireNonNull(list);
            Objects.requireNonNull(map);
            list.forEach(struct -> map.forEach(struct::copy));
        }

        public static void batchMoves(List<HashStruct> list, Map<String, String> map) {
            Objects.requireNonNull(list);
            Objects.requireNonNull(map);
            list.forEach(struct -> map.forEach(struct::move));
        }

        public static void batchExchanges(List<HashStruct> list, Map<String, String> map) {
            Objects.requireNonNull(list);
            Objects.requireNonNull(map);
            list.forEach(struct -> map.forEach(struct::exchange));
        }

    }
}
